namespace SimpleWebServices.Models
{
    using System;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Xml.XPath;
    using SimpleWebServices;
    using SimpleWebServices.Xml;
    using Xunit;

    public sealed class SiteMapUrlFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<SiteMapUrl>()
                .DerivesFrom<ValueObject<SiteMapUrl>>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .XmlRoot("url", "http://www.sitemaps.org/schemas/sitemap/0.9")
                .Implements<IXmlSerializerNamespaces>()
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            SiteMapUrl actual = (
                "<url xmlns='http://www.sitemaps.org/schemas/sitemap/0.9'>" +
                    "<changefreq>weekly</changefreq>" +
                    "<loc>http://example.com/location</loc>" +
                    "<lastmod>1999-12-31T01:02:03</lastmod>" +
                    "<priority>0.5</priority>" +
                "</url>").Deserialize<SiteMapUrl>();

            Assert.NotNull(actual);

            Assert.Equal<string>("weekly", actual.ChangeFrequency);
            Assert.Equal<DateTime>(new DateTime(1999, 12, 31, 1, 2, 3), actual.LastModified.Value);
            Assert.Equal<AbsoluteUri>("http://example.com/location", actual.Location);
            Assert.Equal<float>(0.5f, actual.Priority.Value);
        }

        [Fact]
        public void deserializeEmpty()
        {
            SiteMapUrl actual = "<url xmlns='http://www.sitemaps.org/schemas/sitemap/0.9' />".Deserialize<SiteMapUrl>();

            Assert.NotNull(actual);

            Assert.Null(actual.ChangeFrequency);
            Assert.False(actual.LastModified.HasValue);
            Assert.Null(actual.Location);
            Assert.False(actual.Priority.HasValue);
        }

        [Fact]
        public void serialize()
        {
            SiteMapUrl obj = new SiteMapUrl
            {
                ChangeFrequency = "daily",
                LastModified = new DateTime(1999, 12, 31),
                Location = "http://example.com/location",
                Priority = 0.5f
            };

            XPathNavigator navigator = obj.Serialize().CreateNavigator();
            XmlNamespaceManager namespaces = new XmlNamespaceManager(navigator.NameTable);
            namespaces.AddNamespace("s", "http://www.sitemaps.org/schemas/sitemap/0.9");

            Assert.True((bool)navigator.Evaluate("1=count(/s:url/s:changefreq[text()='daily'])", namespaces));
            Assert.True((bool)navigator.Evaluate("1=count(/s:url/s:lastmod[text()='1999-12-31'])", namespaces));
            Assert.True((bool)navigator.Evaluate("1=count(/s:url/s:loc[text()='http://example.com/location'])", namespaces));
            Assert.True((bool)navigator.Evaluate("1=count(/s:url/s:priority[text()='0.5'])", namespaces));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new SiteMapUrl());
        }

        [Fact]
        public void prop_ChangeFrequency()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrl).GetProperty("ChangeFrequency"))
                .XmlElement("changefreq", "http://www.sitemaps.org/schemas/sitemap/0.9")
                .TypeIs<string>()
                .Set(null as string)
                .ArgumentOutOfRangeException(string.Empty)
                .Set("always")
                .Set("hourly")
                .Set("daily")
                .Set("weekly")
                .Set("monthly")
                .Set("yearly")
                .Set("never")
                .ArgumentOutOfRangeException("foo")
                .Result);
        }

        [Fact]
        public void prop_LastModified()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrl).GetProperty("LastModified"))
                .XmlIgnore()
                .IsAutoProperty<DateTime?>()
                .Result);
        }

        [Fact]
        public void prop_LastModifiedValue()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrl).GetProperty("LastModifiedValue"))
                .XmlElement("lastmod", "http://www.sitemaps.org/schemas/sitemap/0.9")
                .TypeIs<string>()
                .Set(null as string)
                .ArgumentOutOfRangeException(string.Empty)
                .Set("1999-12-31")
                .Set(DateTime.UtcNow.ToXmlString())
                .Result);
        }

        [Fact]
        public void prop_Location()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrl).GetProperty("Location"))
                .XmlIgnore()
                .IsAutoProperty<AbsoluteUri>()
                .Result);
        }

        [Fact]
        public void prop_LocationValue()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrl).GetProperty("LocationValue"))
                .XmlElement("loc", "http://www.sitemaps.org/schemas/sitemap/0.9")
                .TypeIs<string>()
                .Set(null as string)
                .Exception(string.Empty, typeof(UriFormatException))
                .Set("http://example.com/location")
                .Exception("/location", typeof(UriFormatException))
                .Result);
        }

        [Fact]
        public void prop_Priority()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrl).GetProperty("Priority"))
                .XmlIgnore()
                .IsAutoProperty<float?>()
                .Result);
        }

        [Fact]
        public void prop_PriorityValue()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrl).GetProperty("PriorityValue"))
                .XmlElement("priority", "http://www.sitemaps.org/schemas/sitemap/0.9")
                .TypeIs<string>()
                .Set(null as string)
                .ArgumentOutOfRangeException(string.Empty)
                .Set("0.0")
                .Set("0.1")
                .Set("0.2")
                .Set("0.3")
                .Set("0.4")
                .Set("0.5")
                .Set("0.6")
                .Set("0.7")
                .Set("0.8")
                .Set("0.9")
                .Set("1.0")
                .ArgumentOutOfRangeException("1.01")
                .ArgumentOutOfRangeException("1.1")
                .Result);
        }

        [Fact]
        public void prop_XmlNamespaceDeclarations()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrlSet).GetProperty("XmlNamespaceDeclarations"))
                .XmlNamespaceDeclarations()
                .TypeIs<XmlSerializerNamespaces>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_XmlNamespaceDeclarations_get()
        {
            XmlSerializerNamespaces actual = new SiteMapUrlSet().XmlNamespaceDeclarations;

            Assert.Equal<int>(1, actual.Count);

            XmlQualifiedName name = actual.ToArray().GetValue(0) as XmlQualifiedName;
            Assert.Equal<string>(string.Empty, name.Name);
            Assert.Equal<string>("http://www.sitemaps.org/schemas/sitemap/0.9", name.Namespace);
        }
    }
}